<!DOCTYPE html>
<html>

<head>
	<meta charset="utf-8">
	<title></title>
</head>

<body>
	<script type="text/javascript">
		//变量提升相关
		var a = 1;
		function test() {
			var a = 2
			console.log(a)//为2
		}
		function test2() {
			console.log(a)//为undefined
			var a = 2
		}
		function test3() {
			console.log(a)//为1
			a = 2
		}
		let b = 1
		function ts() {
			console.log(b)//为undefined
			let b = 2
		}
		function ts2() {
			console.log(b)//为1
			b = 2
		}
		function ts2() {
			{
				let b = 2
			}
			console.log(b)//为1
		}





		//函数提升相关
		function tst() {
			foo()//调用tst()出来'2222'，提升成功
			function foo() {
				console.log('2222')
			}
			foo2()//调用失败，提示不是函数
			var foo2 = function foo2() {
				console.log('2222')
			}
		}




		//async异步顺序剖析
		async function async1() {
			console.log('async1 start');
			await async2();//不是阻塞，是暂时暂停运行，走其他的
			console.log('async1 end');
		}
		async function async2() {
			console.log('async2');
		}

		console.log('script start');

		setTimeout(function () {
			console.log('setTimeout');
		}, 0)

		async1();

		new Promise(function (resolve) {
			console.log('promise1');
			resolve();
		}).then(function () {
			console.log('promise2');
		});
		console.log('script end');
		/*
			script start // 第一个宏任务
			async1 start // 
			async2		 // 没返回就上面那步await先阻塞搁置下面的，按照线程顺序跑另外的宏任务微任务
			promise1	 // 
			script end	 // 第二个宏任务
			async1 end	 // 
			promise2
			setTimeout
		*/



		//下面打印什么
		var c = 10;
		(function c() {
			c = 20;
			console.log(c);
		})();
		// c被需改了，形成一个函数体，然后直接括号可以调用具名函数，里面同名变量无法修改同名function使function变成20，所以，打印了函数体出来




		//下面如何让a == 1 && a == 2 && a == 3成立？
		var a = {
			i: 1,
			valueOf() {
				return a.i++;
			}
		}
		if (a == 1 && a == 2 && a == 3) {
			console.log(1);
		}


		//下面输出什么？
		var a = 10;//隐性赋值了window和global
		(function () {
			console.log(a)//受var的影响
			a = 5//修改了global的a，window的没变
			console.log(window.a)
			var a = 20;
			console.log(a)
		})()
		//undefined,10,20


		//下面输出了什么？
		var obj = {
			'2': 3,
			'3': 4,
			'length': 2,
			'splice': Array.prototype.splice,
			'push': Array.prototype.push
		}
		obj.push(1)
		obj.push(2)
		console.log(obj)
		//下面两个属性隐性转为了数组，除length，splice，push之外，其他属性直接作废了


		//实现(5).add(2).minus(2)
		// Number.prototype.add = function(n) {
		// 	return this.valueOf() + n;
		// };
		// Number.prototype.minus = function(n) {
		// 	return this.valueOf() - n;
		// };


		var arr = [];
		for (var i = 0; i < 10; i++) {
			var ind = i//有这个并且拿这个的时候，最后第一个打出来比10少个1
			arr.push(function () { console.log(i) })
		}
		arr[0]()


		//连续赋值的问题
		var a = { n: 1 }; // a保持对{n:1}对象的引用
		var b = a; // b保持对{n:1}对象的引用
		a.x = a = { n: 2 }; // a的引用被改变
		//类比a = b = 2,从右到左
		//像上面的a.x = a = { n: 2 }，就是从左到右，先a.x = undefined,然后因为a的引用被改变，所以a.x直接等于{ n: 2 }，再a = { n: 2 }，成员x比右边的执行等级要高


		//属性取值问题
		// example 1 ----- //
		var _a = {}, _b = '123', _c = 123;
		_a[_b] = 'b';

		// c 的键名会被转换成字符串'123'，这里会把 b 覆盖掉。//
		_a[_c] = 'c';

		// 输出 c //
		// example 2 ----- //
		var __a = {}, __b = Symbol('123'), __c = Symbol('123');

		// b 是 Symbol 类型，不需要转换。 //
		__a[__b] = 'b';

		// c 是 Symbol 类型，不需要转换。任何一个 Symbol 类型的值都是不相等的，所以不会覆盖掉 b。 //
		__a[__c] = 'c';

		// 输出 b //
		// example 3 ----- //
		var ___a = {}, ___b = { key: '123' }, ___c = { key: '456' };

		// b 不是字符串也不是 Symbol 类型，需要转换成字符串。 //
		// 对象类型会调用 toString 方法转换成字符串 [object Object]。 //
		___a[___b] = 'b';

		// c 不是字符串也不是 Symbol 类型，需要转换成字符串。 //
		// 对象类型会调用 toString 方法转换成字符串 [object Object]。这里会把 b 覆盖掉。 //
		___a[___c] = 'c';

			// 输出 c //
	</script>
</body>

</html>